{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Table of contents\n",
    "\n",
    "1. [Problem Domain](#Problem-Domain)\n",
    "2. [CNNs for text classification](#CNNs-for-text-classification)\n",
    "3. [Loading data and libraries](#Loading-data-and-libraries)\n",
    "4. [Text preprocessing](#Text-preprocessing)\n",
    "5. [Architecture](#Architecture)\n",
    "6. [Training CNN Model](#Training-CNN-Model)\n",
    "7. [Validation and test set](#Validation-and-test-set)\n",
    "8. [Bi-GRU with attention model](#Bi-GRU-with-attention-model)\n",
    "9. [Training RNN model](#Training-RNN-model)\n",
    "10. [Validation and test set RNN](#Validation-and-test-set-RNN)\n",
    "11. [Further improvements](#Further-Improvements)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Problem Domain ##\n",
    "\n",
    "[Go up](#Table-of-contents)\n",
    "\n",
    "We always need to compute the similarity in meaning between texts.\n",
    "\n",
    "*Search engines*\n",
    "need to model the relevance of a document to a query, beyond the overlap in words between the two. For instance, question-and-answer sites such as Quora or Stackoverflow need to determine whether a question has already been asked before.\n",
    "\n",
    "In *legal matters*, text similarity task allow to mitigate risks on a new contract, based on the assumption that if a new contract is similar to a existent one that has been proved to be resilient, the risk of this new contract being the cause of financial loss is minimised. Here is the principle of Case Law principle. Automatic linking of related documents ensures that identical situations are treated similarly in every case. Text similarity foster fairness and equality. Precedence retrieval of legal documents is an information retrieval task to retrieve prior case documents that are related to a given case document.\n",
    "\n",
    "In *customer services*, AI system should be able to understand semantically similar queries from users and provide a uniform response. The emphasis on semantic similarity aims to create a system that recognizes language and word patterns to craft responses that are similar to how a human conversation works. For example, if the user asks “What has happened to my delivery?” or “What is wrong with my shipping?”, the user will expect the same response.\n",
    "\n",
    "\n",
    "It was used for predicting if one research paper will be cited by the new research paper.\n",
    "\n",
    "Out of numerous approaches that are available to model this problem depending upon the use case, the text length, content type, domain I experimented with quite a few."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## CNNs for text classification ##\n",
    "\n",
    "[Go up](#Table-of-contents)\n",
    " \n",
    "-      A ConvNet is able to successfully capture the Spatial and Temporal dependencies in an image through the application of relevant filters.\n",
    "\n",
    "-       Similar to the Convolutional Layer, the Pooling layer is responsible for reducing the spatial size of the Convolved Feature. This is to decrease the computational power required to process the data through dimensionality reduction. Furthermore, it is useful for extracting dominant featureswhich are rotational and positional invariant, thus maintaining the process of effectively training of the model.\n",
    "\n",
    "-       Max Pooling also performs as a Noise Suppressant. It discards the noisy activations altogether and also performs de-noising along with dimensionality reduction. On the other hand, Average Pooling simply performs dimensionality reduction as a noise suppressing mechanism. Hence, we can say that Max Pooling performs a lot better than Average Pooling.\n",
    "\n",
    "A big argument for CNNs is that they are fast. Very fast. Convolutions are a central part of computer graphics and implemented on a hardware level on GPUs. Compared to something like n-grams, CNNs are also efficient in terms of representation. With a large vocabulary, computing anything more than 3-grams can quickly become expensive. Even Google doesn’t provide anything beyond 5-grams. Convolutional Filters learn good representations automatically, without needing to represent the whole vocabulary. It’s completely reasonable to have filters of size larger than 5. I like to think that many of the learned filters in the first layer are capturing features quite similar (but not limited) to n-grams, but represent them in a more compact way.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "How could CNNs be used for text data?\n",
    "\n",
    "![cnn on text data](http://www.joshuakim.io/wp-content/uploads/2017/12/figure.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loading data and libraries ##\n",
    "\n",
    "[Go up](#Table-of-contents)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "_cell_guid": "b1076dfc-b9ad-4769-8c92-a6c4dae69d19",
    "_uuid": "8f2839f25d086af736a60e9eeb907d3b93b6e0e5"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['fasttext-crawl-300d-2m', 'quora-question-pairs']\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "\n",
    "import numpy as np # linear algebra\n",
    "import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n",
    "from IPython.display import Image\n",
    "\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "import os\n",
    "print(os.listdir(\"../input\"))\n",
    "\n",
    "import numpy as np\n",
    "import multiprocessing as mp\n",
    "import tensorflow as tf\n",
    "from sklearn.metrics import roc_auc_score\n",
    "\n",
    "import string\n",
    "import spacy \n",
    "import en_core_web_sm\n",
    "from nltk.corpus import stopwords\n",
    "from sklearn.feature_extraction import stop_words\n",
    "import gc\n",
    "from sklearn.random_projection import sparse_random_matrix\n",
    "from nltk.tokenize import word_tokenize\n",
    "from sklearn.base import TransformerMixin, BaseEstimator\n",
    "from keras.preprocessing.text import Tokenizer\n",
    "from keras.preprocessing.sequence import pad_sequences\n",
    "from keras.layers import Input, Embedding, BatchNormalization, GRU,LSTM, Dense, Concatenate,Bidirectional, Conv1D, AveragePooling1D,\\\n",
    "                                                    Lambda, CuDNNLSTM, Bidirectional, GlobalMaxPooling1D, GlobalAveragePooling1D,\\\n",
    "                                                    SpatialDropout1D, Dropout, add, concatenate \n",
    "\n",
    "from keras.models import Model\n",
    "from sklearn.feature_extraction.text import TfidfVectorizer\n",
    "\n",
    "from keras.metrics import binary_accuracy\n",
    "from keras.utils import plot_model\n",
    "from keras import backend as K\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "from tqdm import tqdm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "_cell_guid": "79c7e3d0-c299-4dcb-8224-4455121ee9b0",
    "_uuid": "d629ff2d2480ee46fbb7e2d37f6b5fab8052498a"
   },
   "outputs": [],
   "source": [
    "train_data = pd.read_csv(\"../input/quora-question-pairs/train.csv\")\n",
    "test_data = pd.read_csv(\"../input/quora-question-pairs/test.csv\")\n",
    "embedding_dim = 300\n",
    "embedding_file_path = '../input/fasttext-crawl-300d-2m/crawl-300d-2M.vec'\n",
    "train_data, val_data, train_y, val_y = train_test_split(train_data[['question1', 'question2']], train_data['is_duplicate'],\n",
    "                                                        test_size = 0.2,random_state = 999\n",
    "                                           )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# for loading the word vectors I have used code from this excellent kernel: \n",
    "# https://www.kaggle.com/christofhenkel/keras-baseline-lstm-attention-5-fold\n",
    "\n",
    "def get_coefs(word,*arr): return word, np.asarray(arr, dtype='float32')\n",
    "\n",
    "def load_embeddings(embed_dir=embedding_file_path):\n",
    "    embedding_index = dict(get_coefs(*o.strip().split(\" \")) for o in tqdm(open(embed_dir)))\n",
    "    return embedding_index\n",
    "\n",
    "def build_embedding_matrix(word_index, embeddings_index, max_features, lower = True, verbose = True):\n",
    "    embedding_matrix = np.zeros((max_features, 300))\n",
    "    for word, i in tqdm(word_index.items(),disable = not verbose):\n",
    "        if lower:\n",
    "            word = word.lower()\n",
    "        if i >= max_features: continue\n",
    "        try:\n",
    "            embedding_vector = embeddings_index[word]\n",
    "        except:\n",
    "            embedding_vector = embeddings_index[\"unknown\"]\n",
    "        if embedding_vector is not None:\n",
    "            # words not found in embedding index will be all-zeros.\n",
    "            embedding_matrix[i] = embedding_vector\n",
    "    return embedding_matrix\n",
    "\n",
    "def build_matrix(word_index, embeddings_index):\n",
    "    embedding_matrix = np.zeros((len(word_index) + 1,300))\n",
    "    for word, i in word_index.items():\n",
    "        try:\n",
    "            embedding_matrix[i] = embeddings_index[word]\n",
    "        except:\n",
    "            embedding_matrix[i] = embeddings_index[\"unknown\"]\n",
    "    return embedding_matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "maxlen = 20\n",
    "vocab_size = 10000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "#This is very generic list of contractions and most of the words may not even appear in an item description\n",
    "contractions = {\"ain't\": \"is not\", \"aren't\": \"are not\",\"can't\": \"cannot\", \"'cause\": \"because\",\n",
    "                \"could've\": \"could have\", \"couldn't\": \"could not\", \"didn't\": \"did not\",  \"doesn't\": \"does not\",\n",
    "                \"don't\": \"do not\", \"hadn't\": \"had not\", \"hasn't\": \"has not\", \"haven't\": \"have not\", \"he'd\": \"he would\",\n",
    "                \"he'll\": \"he will\", \"he's\": \"he is\", \"how'd\": \"how did\", \"how'd'y\": \"how do you\", \"how'll\": \"how will\",\n",
    "                \"how's\": \"how is\",  \"I'd\": \"I would\", \"I'd've\": \"I would have\", \"I'll\": \"I will\",\n",
    "                \"I'll've\": \"I will have\",\"I'm\": \"I am\", \"I've\": \"I have\", \"i'd\": \"i would\", \"i'd've\": \"i would have\",\n",
    "                \"i'll\": \"i will\",  \"i'll've\": \"i will have\",\"i'm\": \"i am\", \"i've\": \"i have\", \"isn't\": \"is not\", \n",
    "                \"it'd\": \"it would\", \"it'd've\": \"it would have\", \"it'll\": \"it will\", \"it'll've\": \"it will have\",\n",
    "                \"it's\": \"it is\", \"let's\": \"let us\", \"ma'am\": \"madam\", \"mayn't\": \"may not\", \"might've\": \"might have\",\n",
    "                \"mightn't\": \"might not\",\"mightn't've\": \"might not have\", \"must've\": \"must have\", \"mustn't\": \"must not\",\n",
    "                \"mustn't've\": \"must not have\", \"needn't\": \"need not\", \"needn't've\": \"need not have\",\n",
    "                \"o'clock\": \"of the clock\", \"oughtn't\": \"ought not\", \"oughtn't've\": \"ought not have\",\n",
    "                \"shan't\": \"shall not\", \"sha'n't\": \"shall not\", \"shan't've\": \"shall not have\", \"she'd\": \"she would\",\n",
    "                \"she'd've\": \"she would have\", \"she'll\": \"she will\", \"she'll've\": \"she will have\", \"she's\": \"she is\", \n",
    "                \"should've\": \"should have\", \"shouldn't\": \"should not\", \"shouldn't've\": \"should not have\", \n",
    "                \"so've\": \"so have\",\"so's\": \"so as\", \"this's\": \"this is\",\"that'd\": \"that would\", \n",
    "                \"that'd've\": \"that would have\", \"that's\": \"that is\", \"there'd\": \"there would\", \n",
    "                \"there'd've\": \"there would have\", \"there's\": \"there is\", \"here's\": \"here is\",\"they'd\": \"they would\",\n",
    "                \"they'd've\": \"they would have\", \"they'll\": \"they will\", \"they'll've\": \"they will have\", \n",
    "                \"they're\": \"they are\", \"they've\": \"they have\", \"to've\": \"to have\", \"wasn't\": \"was not\", \n",
    "                \"we'd\": \"we would\", \"we'd've\": \"we would have\", \"we'll\": \"we will\", \"we'll've\": \"we will have\", \n",
    "                \"we're\": \"we are\", \"we've\": \"we have\", \"weren't\": \"were not\", \"what'll\": \"what will\", \n",
    "                \"what'll've\": \"what will have\", \"what're\": \"what are\",  \"what's\": \"what is\", \"what've\": \"what have\",\n",
    "                \"when's\": \"when is\", \"when've\": \"when have\", \"where'd\": \"where did\", \"where's\": \"where is\", \n",
    "                \"where've\": \"where have\", \"who'll\": \"who will\", \"who'll've\": \"who will have\", \"who's\": \"who is\", \n",
    "                \"who've\": \"who have\", \"why's\": \"why is\", \"why've\": \"why have\", \"will've\": \"will have\", \n",
    "                \"won't\": \"will not\", \"won't've\": \"will not have\", \"would've\": \"would have\", \"wouldn't\": \"would not\",\n",
    "                \"wouldn't've\": \"would not have\", \"y'all\": \"you all\", \"y'all'd\": \"you all would\",\n",
    "                \"y'all'd've\": \"you all would have\",\"y'all're\": \"you all are\",\"y'all've\": \"you all have\",\n",
    "                \"you'd\": \"you would\", \"you'd've\": \"you would have\", \"you'll\": \"you will\", \"you'll've\": \"you will have\", \n",
    "                \"you're\": \"you are\", \"you've\": \"you have\" }\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Text preprocessing ##\n",
    "\n",
    "[Go up](#Table-of-contents)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TextPreprocessor(BaseEstimator, TransformerMixin):\n",
    "    def __init__(self,\n",
    "                 contractions={},\n",
    "                 stop_words={},\n",
    "                 spellings={},\n",
    "                 user_abbrevs={},\n",
    "                 n_jobs=1):\n",
    "        \"\"\"\n",
    "        Text preprocessing transformer includes steps:\n",
    "            1. Text normalization\n",
    "            2. contractions\n",
    "            3. Punctuation removal\n",
    "            4. Stop words removal - words like not are excluded from stop words\n",
    "        \"\"\"\n",
    "       \n",
    "        self.user_abbrevs = user_abbrevs\n",
    "        self.n_jobs = n_jobs\n",
    "        self.contractions = contractions\n",
    "        self.stop_words = stop_words\n",
    "        self.spellings = spellings\n",
    "        \n",
    "    def fit(self, X, y=None):\n",
    "        return self\n",
    "\n",
    "    def transform(self, X, *_):\n",
    "        X_copy = X.copy()\n",
    "\n",
    "        partitions = 1\n",
    "        cores = mp.cpu_count()\n",
    "        if self.n_jobs <= -1:\n",
    "            partitions = cores\n",
    "        elif self.n_jobs <= 0:\n",
    "            return X_copy.apply(self._preprocess_text)\n",
    "        else:\n",
    "            partitions = min(self.n_jobs, cores)\n",
    "\n",
    "        data_split = np.array_split(X_copy, partitions)   # split data for parallel processing\n",
    "        pool = mp.Pool(cores)                           # create pools\n",
    "        data = pd.concat(pool.map(self._preprocess_part, data_split))   # concatenate results\n",
    "        pool.close()                                  \n",
    "        pool.join()\n",
    "\n",
    "        return data\n",
    "\n",
    "    def _preprocess_part(self, part):\n",
    "        return part.apply(self._preprocess_text)\n",
    "\n",
    "    def _preprocess_text(self, text):\n",
    "        lowercase_text = self._lowercase(text)\n",
    "        expanded_contractions = self._expand_contactions(lowercase_text)\n",
    "        \n",
    "        return (expanded_contractions)\n",
    "   \n",
    "    def _lowercase(self, text):\n",
    "        return text.lower()\n",
    "        \n",
    "    def _expand_contactions(self, doc):\n",
    "        new_text = \"\"\n",
    "        for t in doc.split():\n",
    "            if (t in string.punctuation) or (t in self.stop_words) or (t in string.punctuation):\n",
    "                continue\n",
    "            if t in contractions:\n",
    "                new_text = new_text + \" \" + (contractions[t])\n",
    "            else: \n",
    "                new_text = new_text + \" \" + t\n",
    "        return new_text\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "refined_stop_words = stop_words.ENGLISH_STOP_WORDS - {\"not\", \"none\", \"nothing\", \"nowhere\", \"never\", \"cannot\",\n",
    "                                \"cant\", \"couldnt\", \"except\", \"hasnt\", \"neither\", \"no\", \n",
    "                                 \"nobody\", \"nor\", \"without\", \"when\", \"why\",\"whom\",\"who\",\"what\",\"where\",\"how\"}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 0 ns, sys: 0 ns, total: 0 ns\n",
      "Wall time: 10.3 µs\n"
     ]
    }
   ],
   "source": [
    "%time\n",
    "\n",
    "train_data[\"question1\"] = train_data[\"question1\"].fillna(\"None\")\n",
    "train_data[\"question2\"] = train_data[\"question2\"].fillna(\"None\")\n",
    "val_data[\"question1\"] = val_data[\"question1\"].fillna(\"None\")\n",
    "val_data[\"question2\"] = val_data[\"question2\"].fillna(\"None\")\n",
    "test_data[\"question1\"] = test_data[\"question1\"].fillna(\"None\")\n",
    "test_data[\"question2\"] = test_data[\"question2\"].fillna(\"None\")\n",
    "\n",
    "\n",
    "train_data['question1'] = train_data['question1'].astype(str)\n",
    "train_data['question2'] = train_data['question2'].astype(str)\n",
    "val_data['question1'] = val_data['question1'].astype(str)\n",
    "val_data['question2'] = val_data['question2'].astype(str)\n",
    "test_data['question1'] = test_data['question1'].astype(str)\n",
    "test_data['question2'] = test_data['question2'].astype(str)\n",
    "\n",
    "textPreprocessor = TextPreprocessor(n_jobs=-1, contractions=contractions,\n",
    "                 stop_words=refined_stop_words)\n",
    "    \n",
    "train_data['question1'] = textPreprocessor.transform(train_data['question1'])\n",
    "train_data['question2'] = textPreprocessor.transform(train_data['question2'])\n",
    "val_data['question1'] = textPreprocessor.transform(val_data['question1'])\n",
    "val_data['question2'] = textPreprocessor.transform(val_data['question2'])\n",
    "test_data['question1'] = textPreprocessor.transform(test_data['question1'])\n",
    "test_data['question2'] = textPreprocessor.transform(test_data['question2'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "#intsantiate the tokenizer\n",
    "tokenize = Tokenizer(num_words = vocab_size, oov_token='OOV')\n",
    "tokenize.fit_on_texts(np.hstack([train_data['question1'], train_data['question2'],\n",
    "                                 test_data['question1'],test_data['question2']]))\n",
    "vocabulary = tokenize.word_index\n",
    "\n",
    "# sentences to sequences\n",
    "train_data['sequence_1'] = tokenize.texts_to_sequences(train_data['question1'])\n",
    "train_data['sequence_2'] = tokenize.texts_to_sequences(train_data['question2'])\n",
    "val_data['sequence_1'] = tokenize.texts_to_sequences(val_data['question1'])\n",
    "val_data['sequence_2'] = tokenize.texts_to_sequences(val_data['question2'])\n",
    "test_data['sequence_1'] = tokenize.texts_to_sequences(test_data['question1'])\n",
    "test_data['sequence_2'] = tokenize.texts_to_sequences(test_data['question2'])\n",
    "\n",
    "train_padded = {}\n",
    "test_padded = {}\n",
    "val_padded = {}\n",
    "\n",
    "train_padded['sequence_1'] = pad_sequences(train_data['sequence_1'], maxlen = maxlen)\n",
    "train_padded['sequence_2'] = pad_sequences(train_data['sequence_2'], maxlen = maxlen)\n",
    "val_padded['sequence_1'] = pad_sequences(val_data['sequence_1'], maxlen = maxlen)\n",
    "val_padded['sequence_2'] = pad_sequences(val_data['sequence_2'], maxlen = maxlen)\n",
    "test_padded['sequence_1'] = pad_sequences(test_data['sequence_1'], maxlen = maxlen)\n",
    "test_padded['sequence_2'] = pad_sequences(test_data['sequence_2'], maxlen = maxlen)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2000001it [02:56, 11323.52it/s]\n"
     ]
    }
   ],
   "source": [
    "embeddings_index = load_embeddings()\n",
    "embedding_matrix = build_matrix(tokenize.word_index, embeddings_index)\n",
    "del embeddings_index\n",
    "#gc.collect()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# I'm also tracking auc, to understand how well this model might be able to separate the two classes\n",
    "def auroc(y_true, y_pred):\n",
    "    return tf.py_func(roc_auc_score, (y_true, y_pred), tf.double)\n"
   ]
  },
  {
   "attachments": {
    "image.png": {
     "image/png": "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qSmtTciIkg/8+iolO35EWYQQInd+ZmhUqdkRG6qaq0pq4zMGPJSwpqzBJ8A7PNb85Ht8RqxZdVYRQAABBBBAAAG3ESCRcJtQuvlAMi8Z4lGAFUW1g4etUntnX5k5+m+qQqKCQqLMH+Jh+KZq8EHHpUfxTdVgFrYggAACCCCAgBsLcFWfGweXoSGAAAIIIIAAAggg4CgBEglHydIuAggggAACCCCAAAJuLEAi4cbBZWgIIIAAAggggAACCDhKgETCUbK0iwACCCCAAAIIIICAGwuQSLhxcBkaAggggAACCCCAAAKOEiCRcJQs7SKAAAIIIIAAAggg4MYCJBJuHFyGhgACCCCAAAIIIICAowRIJBwlS7sIIIAAAggggAACCLixAImEGweXoSGAAAIIIIAAAggg4CgBEglHydIuAggggAACCCCAAAJuLEAi4cbBZWgIIIAAAggggAACCDhKgETCUbK0iwACCCCAAAIIIICAGwuQSLhxcBkaAggggAACCCCAAAKOEiCRcJQs7SKAAAIIIIAAAggg4MYCJBJuHFyGhgACCCCAAAIIIICAowRIJBwlS7sIIIAAAggggAACCLixAImEGweXoSGAAAIIIIAAAggg4CgBEglHydIuAggggAACCCCAAAJuLEAi4cbBZWgIIIAAAggggAACCDhKgETCUbK0iwACCCCAAAIIIICAGwuQSLhxcBkaAggggAACCCCAAAKOEiCRcJQs7SKAAAIIIIAAAggg4MYCJBJuHFyGhgACCCCAAAIIIICAowRIJBwlS7sIIIAAAggggAACCLixAImEGweXoSGAAAIIIIAAAggg4CgBEglHydIuAggggAACCCCAAAJuLEAi4cbBZWgIIIAAAggggAACCDhKgETCUbK0iwACCCCAAAIIIICAGwuQSLhxcBkaAggggAACCCCAAAKOEiCRcJQs7SKAAAIIIIAAAggg4MYCJBJuHFyGhgACCCCAAAIIIICAowRIJBwlS7sIIIAAAggggAACCLixAImEGweXoSGAAAIIIIAAAggg4CgBEglHydIuAggggAACCCCAAAJuLEAi4cbBZWgIIIAAAggggAACCDhKgETCUbK0iwACCCCAAAIIIICAGwuQSLhxcBkaAggggAACCCCAAAKOEiCRcJQs7SKAAAIIIIAAAggg4MYCJBJuHFyGhgACCCCAAAIIIICAowRIJBwlS7sIIIAAAggggAACCLixAImEGweXoSGAAAIIIIAAAggg4CgBEglHydIuAggggAACCCCAAAJuLEAi4cbBZWgIIIAAAggggAACCDhKgETCUbK0iwACCCCAAAIIIICAGwuQSLhxcBkaAggggAACCCCAAAKOEiCRcJQs7SKAAAIIIIAAAggg4MYCJBJuHFyGhgACCCCAAAIIIICAowRIJBwlS7sIIIAAAggggAACCLixAImEGweXoSGAAAIIIIAAAggg4CgBEglHydIuAggggAACCCCAAAJuLEAi4cbBZWgIIIAAAggggAACCDhKgETCUbK0iwACCCCAAAIIIICAGwuQSLhxcBkaAggggAACCCCAAAKOEiCRcJQs7SKAAAIIIIAAAggg4MYCJBJuHFyGhgACCCCAAAIIIICAowRIJBwlS7sIIIAAAggggAACCLixAImEGweXoSGAAAIIIIAAAggg4CgBEglHydIuAggggAACCCCAAAJuLKB047ExNAQQQAAB+wocbGjaXVPf3K21b7O0NkqBWF/11dGRMT6qUbZDdQRMBZjvphrSWZbUfLdbItGi1X5UWLK7lg8Y6bzSzvck1kd9XVz0d8dFS65ndMhlBZjvkg2dQ+f7S8dO/TG/QLJj9/COqRXy5ZfPmh0e4uEODN9eAsx3e0k6oh3pzHe7JRL37DywsarWEVi0OXqBZSXlf5iWtTglYfRN0QICQgjmu5RfBo6b7385dUbKA/fwvnX26P588szs8FwPd2D49hJgvttL0hHtSGe+2+ceifaenk1kEY54pdivzc/PlduvMVryaAHmu/TD74j5fqqltbNHJ/2xe3IPi9vaPXn4jN2OAsx3O2I6qCmJzHf7JBJl7Z16BznRrJ0Eqjs1dmqJZjxdgPku/VeAI+a7TMikP3AP76FGR6bn4S8Buw2f+W43Soc1JJH5bp9EwmFKNIwAAggggAACCCCAAAJSFCCRkGJU6BMCCCCAAAIIIIAAAhIXIJGQeIDoHgIIIIAAAggggAACUhQgkZBiVOgTAggggAACCCCAAAISFyCRkHiA6B4CCCCAAAIIIIAAAlIUIJGQYlToEwIIIIAAAggggAACEhcgkZB4gOgeAggggAACCCCAAAJSFCCRkGJU6BMCCCCAAAIIIIAAAhIXIJGQeIDoHgIIIIAAAggggAACUhQg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V16ZNWtWTExMU1PTlVde+emnn86aNevHP/5xcnLye++9t3DhQmt6SBkEEDAT4NImMxBWHStg+gGzc+dOtVr9wx/+8MEHHxz2qIYPGJVK9fDDD+fl5a1bt27v3r15eXmGD5ht27YtX778kksuEUIM/oB59tlng4KCHnnkkby8vH/84x9Hjx7du3evQqEwfsB88skns2fPNn7AVFdX33rrrYmJifv27Xvvvff2799v+FZs2E5SAAEEEEDAcAnr1r4fg8auXbtOnTr12muvWcb56quvMjIyvvOd77z66qsajSYsLKy+vn7Tpk133XXXww8/bHif/8Mf/iCEMFw0NXv27EmTJjU3N7/88stCiD/+8Y+GvGLWrFl79uxZvnz5HXfcYTjioUOHdu7cafiM2LhxY3V1dVxc3NKlS2UymU6n+81vfhMSEtLW1ubn52e5h+xFAAEzARIJMxBWHSvAB4xjfWkdAQQQcLZAdHT0nDlzQkNDX3zxxfj4+CeeeOLDDz988803H3vssXHjxlno3fvvv2/Yq9Fo9Hp9TExMQUFBWVmZEOLWW2+NiooqKio6cODAtGnTDInEvffeK4TYu3dvZ2fvQyBTUlJKS0uFELm5uXv27Nm6dasxkZgwYYIhixBCJCYmKpXKsrKySZMmLVq06LLLLnv00UdtuxDLwljYhYCHCHBpk4cEWirDNHzA3HjjjYcPH66vrzd8e/Tmm28a3v0t9PL9998/ceKE4WsqwweM4eSD2QeM8ZuqIT9gSktLc3NzhRBbt241HutiHzA/+9nPVq5c+eijjz7yyCN8TWXkYgEBBBCwLPCrX/1q+/btq1atmjJlSkhIiOF0QU9Pz+HDhy1X3Ldv3zXXXOPv769Wq318fAoKCoQQer1eCOHl5XXfffcZrm7q6OjYuHGjn5/fnXfeKYRobGw0NHvFFVfE9/28/fbbxg8Iw67o6GjjoVNSUpYuXZqcnJyfn//666/fcsstsbGxL730krEACwggYL0AiYT1VpS0gwAfMHZApAkEEEBAwgI1NTV5eXm1tbWGPnp7exsWDOcNLtbxhoaGa6655uuvv77ppps2bty4a9euuLg408IPPvigQqFYvnz5N998097efscddwQEBAghQkJCDMX+9re/fWny84tf/MJYXaFQGJeFEDfddNOZM2fy8vI+/PDDW265paOj4+mnn968ebNpGZYRQMAaAS5tskaJMnYTqOn7iYyMDA8PF0KM6AOmsbHxv//7v++9914fH5/bbrvNcL7b0LMHH3zwlVdeMdwm0d7evnjx4sEfMIYjGsqHhYUZhzT4A+amm27Kz8/fvXv36tWrV6xY8fTTT8+ZM+eKK64wVmEBAQQQ8DSBI0eOfP7550KIZ555Ri6Xr1q16sCBAwkJCYYTy2+99VZ9ff3ll19+1VVXLViw4NChQ7feeuu///1vpVL51ltvCSHkcvmsWbMsoOXl5RnOLfz85z+fOnXqmTNnKisrhRDd3d2GWvHx8TfccMPKlSt/97vfCSEMp50NFzKp1erOzk5fX1/Dn71bv359c3NzaGjokIfbsWPHmjVrcnJybrvttokTJy5evDg3N/fAgQPFxcVDlmcjAghYECCRsIDDLmsF+ICxVopyCCCAgGsKHDly5PnnnxdCPP3004ZE4oMPPpgzZ44xkSgsLHzqqaeuuuqqZ5555pZbblm+fHlsbKxarT537pwQ4ic/+YnlGyTS09NVKpVGo3nsscdmzpy5ZMmSuXPnbtmy5eOPP05OTr7rrruEEA8//PDKlSu3b98+YcKEOXPmGCCDgoKeeOKJF198cfHixWvXrm1ra1u2bJlKpTK9hNWUvLu7++WXX1apVOvWrQsPDy8oKDh48GBoaOj8+fNNi7GMAALWCHBpkzVKlBlGwPAB8/zzz+t0OiHEqlWrnn/++Q8//NBQ7a233nr++ec3btxo+CrLcJFrbGxsQkKC4ZHeVn7ACCEee+yxJ598ct68eXPnzhVCfPzxx//+978NR3n44YeFEEN+wAghFi9efM8999x5553XXnvtD37wg5aWliGHZPiAufvuu++///5f/epXt99+Ox8wQ0KxEQEEELiYwM0337x69erLLrtMp9NVV1dPnTr1n//85xtvvHGx8obtERERS5YsycjI2Llz55dffvnGG2988MEH6enpp0+f3rZtm6HM1Vdf7e/vb3o6wrD9hRdeeOutt5KSkpYsWfLVV19dffXVW7ZsmT59+pBHvOKKK1avXj1r1qxly5a99tpru3btuv3227ds2WI5zxmyKTYigABnJHgNjKmA4QPmd7/7XV5enuED5oknnvj+979vuROGD5innnpq586dVVVVb7zxRnZ29nXXXWf4gDF8U2X4gGltbTWe7za0+cILL0RG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"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Architecture ##\n",
    "\n",
    "[Go up](#Table-of-contents)\n",
    "\n",
    "![image.png](attachment:image.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# CNN model with maxpool and fasttext word embeddings\n",
    "\n",
    "def CNN_Model(emb_matrix):\n",
    "    emb_layer = Embedding(\n",
    "        input_dim=emb_matrix.shape[0],\n",
    "        output_dim=emb_matrix.shape[1],\n",
    "        weights=[emb_matrix],\n",
    "        input_length=maxlen,\n",
    "        trainable=False\n",
    "    )\n",
    "    \n",
    "    # 1D convolutions that can iterate over the word vectors\n",
    "    conv1 = Conv1D(filters=128, kernel_size=1, padding='same', activation='relu')\n",
    "    conv2 = Conv1D(filters=128, kernel_size=2, padding='same', activation='relu')\n",
    "    conv3 = Conv1D(filters=128, kernel_size=3, padding='same', activation='relu')\n",
    "    conv4 = Conv1D(filters=128, kernel_size=4, padding='same', activation='relu')\n",
    "    conv5 = Conv1D(filters=32, kernel_size=5, padding='same', activation='relu')\n",
    "    conv6 = Conv1D(filters=32, kernel_size=6, padding='same', activation='relu')\n",
    "\n",
    "\n",
    "    # Define inputs\n",
    "    seq1 = Input(shape=(maxlen,))\n",
    "    seq2 = Input(shape=(maxlen,))\n",
    "\n",
    "    # Run inputs through embedding\n",
    "    emb1 = emb_layer(seq1)\n",
    "    emb2 = emb_layer(seq2)\n",
    "\n",
    "    # Run through CONV + GAP layers\n",
    "    conv1a = conv1(emb1)\n",
    "    glob1a = GlobalMaxPooling1D()(conv1a)\n",
    "    conv1b = conv1(emb2)\n",
    "    glob1b = GlobalMaxPooling1D()(conv1b)\n",
    "\n",
    "    conv2a = conv2(emb1)\n",
    "    glob2a = GlobalMaxPooling1D()(conv2a)\n",
    "    conv2b = conv2(emb2)\n",
    "    glob2b = GlobalMaxPooling1D()(conv2b)\n",
    "\n",
    "    conv3a = conv3(emb1)\n",
    "    glob3a = GlobalMaxPooling1D()(conv3a)\n",
    "    conv3b = conv3(emb2)\n",
    "    glob3b = GlobalMaxPooling1D()(conv3b)\n",
    "\n",
    "    conv4a = conv4(emb1)\n",
    "    glob4a = GlobalMaxPooling1D()(conv4a)\n",
    "    conv4b = conv4(emb2)\n",
    "    glob4b = GlobalMaxPooling1D()(conv4b)\n",
    "\n",
    "    conv5a = conv5(emb1)\n",
    "    glob5a = GlobalMaxPooling1D()(conv5a)\n",
    "    conv5b = conv5(emb2)\n",
    "    glob5b = GlobalMaxPooling1D()(conv5b)\n",
    "\n",
    "    conv6a = conv6(emb1)\n",
    "    glob6a = GlobalMaxPooling1D()(conv6a)\n",
    "    conv6b = conv6(emb2)\n",
    "    glob6b = GlobalMaxPooling1D()(conv6b)\n",
    "\n",
    "    mergea = concatenate([glob1a, glob2a, glob3a, glob4a, glob5a, glob6a])\n",
    "    mergeb = concatenate([glob1b, glob2b, glob3b, glob4b, glob5b, glob6b])\n",
    "\n",
    "    # We take the explicit absolute difference between the two sentences\n",
    "    # Furthermore we take the multiply different entries to get a different measure of equalness\n",
    "    diff = Lambda(lambda x: K.abs(x[0] - x[1]), output_shape=(4 * 128 + 2*32,))([mergea, mergeb])\n",
    "    mul = Lambda(lambda x: x[0] * x[1], output_shape=(4 * 128 + 2*32,))([mergea, mergeb])\n",
    "    \n",
    "    # Merge the Magic and distance features with the difference layer\n",
    "    merge = concatenate([diff, mul])\n",
    "\n",
    "    # The MLP that determines the outcome\n",
    "    x = Dropout(0.2)(merge)\n",
    "    x = BatchNormalization()(x)\n",
    "    x = Dense(300, activation='relu')(x)\n",
    "\n",
    "    x = Dropout(0.2)(x)\n",
    "    x = BatchNormalization()(x)\n",
    "    x = Dense(100, activation='relu', )(x)\n",
    "\n",
    "    x = Dropout(0.2)(x)\n",
    "    x = BatchNormalization()(x)\n",
    "    pred = Dense(1, activation='sigmoid')(x)\n",
    "\n",
    "    # model = Model(inputs=[seq1, seq2, magic_input, distance_input], outputs=pred)\n",
    "    model = Model(inputs=[seq1, seq2], outputs=pred)\n",
    "    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc', auroc])\n",
    "\n",
    "    return model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__________________________________________________________________________________________________\n",
      "Layer (type)                    Output Shape         Param #     Connected to                     \n",
      "==================================================================================================\n",
      "input_1 (InputLayer)            (None, 20)           0                                            \n",
      "__________________________________________________________________________________________________\n",
      "input_2 (InputLayer)            (None, 20)           0                                            \n",
      "__________________________________________________________________________________________________\n",
      "embedding_1 (Embedding)         (None, 20, 300)      39264300    input_1[0][0]                    \n",
      "                                                                 input_2[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "conv1d_1 (Conv1D)               (None, 20, 128)      38528       embedding_1[0][0]                \n",
      "                                                                 embedding_1[1][0]                \n",
      "__________________________________________________________________________________________________\n",
      "conv1d_2 (Conv1D)               (None, 20, 128)      76928       embedding_1[0][0]                \n",
      "                                                                 embedding_1[1][0]                \n",
      "__________________________________________________________________________________________________\n",
      "conv1d_3 (Conv1D)               (None, 20, 128)      115328      embedding_1[0][0]                \n",
      "                                                                 embedding_1[1][0]                \n",
      "__________________________________________________________________________________________________\n",
      "conv1d_4 (Conv1D)               (None, 20, 128)      153728      embedding_1[0][0]                \n",
      "                                                                 embedding_1[1][0]                \n",
      "__________________________________________________________________________________________________\n",
      "conv1d_5 (Conv1D)               (None, 20, 32)       48032       embedding_1[0][0]                \n",
      "                                                                 embedding_1[1][0]                \n",
      "__________________________________________________________________________________________________\n",
      "conv1d_6 (Conv1D)               (None, 20, 32)       57632       embedding_1[0][0]                \n",
      "                                                                 embedding_1[1][0]                \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_1 (GlobalM (None, 128)          0           conv1d_1[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_3 (GlobalM (None, 128)          0           conv1d_2[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_5 (GlobalM (None, 128)          0           conv1d_3[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_7 (GlobalM (None, 128)          0           conv1d_4[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_9 (GlobalM (None, 32)           0           conv1d_5[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_11 (Global (None, 32)           0           conv1d_6[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_2 (GlobalM (None, 128)          0           conv1d_1[1][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_4 (GlobalM (None, 128)          0           conv1d_2[1][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_6 (GlobalM (None, 128)          0           conv1d_3[1][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_8 (GlobalM (None, 128)          0           conv1d_4[1][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_10 (Global (None, 32)           0           conv1d_5[1][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "global_max_pooling1d_12 (Global (None, 32)           0           conv1d_6[1][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "concatenate_1 (Concatenate)     (None, 576)          0           global_max_pooling1d_1[0][0]     \n",
      "                                                                 global_max_pooling1d_3[0][0]     \n",
      "                                                                 global_max_pooling1d_5[0][0]     \n",
      "                                                                 global_max_pooling1d_7[0][0]     \n",
      "                                                                 global_max_pooling1d_9[0][0]     \n",
      "                                                                 global_max_pooling1d_11[0][0]    \n",
      "__________________________________________________________________________________________________\n",
      "concatenate_2 (Concatenate)     (None, 576)          0           global_max_pooling1d_2[0][0]     \n",
      "                                                                 global_max_pooling1d_4[0][0]     \n",
      "                                                                 global_max_pooling1d_6[0][0]     \n",
      "                                                                 global_max_pooling1d_8[0][0]     \n",
      "                                                                 global_max_pooling1d_10[0][0]    \n",
      "                                                                 global_max_pooling1d_12[0][0]    \n",
      "__________________________________________________________________________________________________\n",
      "lambda_1 (Lambda)               (None, 576)          0           concatenate_1[0][0]              \n",
      "                                                                 concatenate_2[0][0]              \n",
      "__________________________________________________________________________________________________\n",
      "lambda_2 (Lambda)               (None, 576)          0           concatenate_1[0][0]              \n",
      "                                                                 concatenate_2[0][0]              \n",
      "__________________________________________________________________________________________________\n",
      "concatenate_3 (Concatenate)     (None, 1152)         0           lambda_1[0][0]                   \n",
      "                                                                 lambda_2[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "dropout_1 (Dropout)             (None, 1152)         0           concatenate_3[0][0]              \n",
      "__________________________________________________________________________________________________\n",
      "batch_normalization_1 (BatchNor (None, 1152)         4608        dropout_1[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dense_1 (Dense)                 (None, 300)          345900      batch_normalization_1[0][0]      \n",
      "__________________________________________________________________________________________________\n",
      "dropout_2 (Dropout)             (None, 300)          0           dense_1[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "batch_normalization_2 (BatchNor (None, 300)          1200        dropout_2[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dense_2 (Dense)                 (None, 100)          30100       batch_normalization_2[0][0]      \n",
      "__________________________________________________________________________________________________\n",
      "dropout_3 (Dropout)             (None, 100)          0           dense_2[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "batch_normalization_3 (BatchNor (None, 100)          400         dropout_3[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dense_3 (Dense)                 (None, 1)            101         batch_normalization_3[0][0]      \n",
      "==================================================================================================\n",
      "Total params: 40,136,785\n",
      "Trainable params: 869,381\n",
      "Non-trainable params: 39,267,404\n",
      "__________________________________________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "cnn_model = CNN_Model(embedding_matrix)\n",
    "cnn_model.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Training CNN Model ##\n",
    "\n",
    "[Go up](#Table-of-contents)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/2\n",
      "323432/323432 [==============================] - 600s 2ms/step - loss: 0.2010 - acc: 0.7788 - auroc: 0.8776\n",
      "Epoch 2/2\n",
      " 35328/323432 [==>...........................] - ETA: 8:50 - loss: 0.1775 - acc: 0.8126 - auroc: 0.9122"
     ]
    }
   ],
   "source": [
    "cnn_model.fit([train_padded['sequence_1'],train_padded['sequence_2']], train_y, class_weight={0:0.64,1:0.36}, epochs = 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Validation and test set ##\n",
    "\n",
    "[Go up](#Table-of-contents)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "80858/80858 [==============================] - 57s 709us/step\n"
     ]
    }
   ],
   "source": [
    "val_preds = cnn_model.predict([val_padded['sequence_1'], val_padded['sequence_2']])\n",
    "cnn_model.evaluate([val_padded['sequence_1'], val_padded['sequence_2']], val_y)\n",
    "submission = pd.DataFrame(index = val_data.index, columns = ['cv_id', 'is_duplicate'])\n",
    "submission['val_id'] = val_data.index\n",
    "submission['is_duplicate'] = val_preds\n",
    "submission.to_csv('val_conv_submission.csv', index=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "cnn_predictions = cnn_model.predict([test_padded['sequence_1'],test_padded['sequence_2']])\n",
    "submission = pd.DataFrame(index = test_data.index, columns = ['test_id', 'is_duplicate'])\n",
    "submission['test_id'] = test_data.index\n",
    "submission['is_duplicate'] = cnn_predictions\n",
    "submission.to_csv('conv_submission.csv', index=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Bi-GRU with attention model ##\n",
    "\n",
    "[Go up](#Table-of-contents)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "# https://www.kaggle.com/suicaokhoailang/lstm-attention-baseline-0-652-lb\n",
    "from keras.layers import *\n",
    "class Attention(Layer):\n",
    "    def __init__(self, step_dim,\n",
    "                 W_regularizer=None, b_regularizer=None,\n",
    "                 W_constraint=None, b_constraint=None,\n",
    "                 bias=True, **kwargs):\n",
    "        self.supports_masking = True\n",
    "        self.init = initializers.get('glorot_uniform')\n",
    "\n",
    "        self.W_regularizer = regularizers.get(W_regularizer)\n",
    "        self.b_regularizer = regularizers.get(b_regularizer)\n",
    "\n",
    "        self.W_constraint = constraints.get(W_constraint)\n",
    "        self.b_constraint = constraints.get(b_constraint)\n",
    "\n",
    "        self.bias = bias\n",
    "        self.step_dim = step_dim\n",
    "        self.features_dim = 0\n",
    "        super(Attention, self).__init__(**kwargs)\n",
    "\n",
    "    def build(self, input_shape):\n",
    "        assert len(input_shape) == 3\n",
    "\n",
    "        self.W = self.add_weight((input_shape[-1],),\n",
    "                                 initializer=self.init,\n",
    "                                 name='{}_W'.format(self.name),\n",
    "                                 regularizer=self.W_regularizer,\n",
    "                                 constraint=self.W_constraint)\n",
    "        self.features_dim = input_shape[-1]\n",
    "\n",
    "        if self.bias:\n",
    "            self.b = self.add_weight((input_shape[1],),\n",
    "                                     initializer='zero',\n",
    "                                     name='{}_b'.format(self.name),\n",
    "                                     regularizer=self.b_regularizer,\n",
    "                                     constraint=self.b_constraint)\n",
    "        else:\n",
    "            self.b = None\n",
    "\n",
    "        self.built = True\n",
    "\n",
    "    def compute_mask(self, input, input_mask=None):\n",
    "        return None\n",
    "\n",
    "    def call(self, x, mask=None):\n",
    "        features_dim = self.features_dim\n",
    "        step_dim = self.step_dim\n",
    "\n",
    "        eij = K.reshape(K.dot(K.reshape(x, (-1, features_dim)),\n",
    "                        K.reshape(self.W, (features_dim, 1))), (-1, step_dim))\n",
    "\n",
    "        if self.bias:\n",
    "            eij += self.b\n",
    "\n",
    "        eij = K.tanh(eij)\n",
    "\n",
    "        a = K.exp(eij)\n",
    "\n",
    "        if mask is not None:\n",
    "            a *= K.cast(mask, K.floatx())\n",
    "\n",
    "        a /= K.cast(K.sum(a, axis=1, keepdims=True) + K.epsilon(), K.floatx())\n",
    "\n",
    "        a = K.expand_dims(a)\n",
    "        weighted_input = x * a\n",
    "        return K.sum(weighted_input, axis=1)\n",
    "\n",
    "    def compute_output_shape(self, input_shape):\n",
    "        return input_shape[0],  self.features_dim"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "def RNN_Model(embedding_matrix):\n",
    "    input_1 = Input(shape=(maxlen,))\n",
    "    input_2 = Input(shape=(maxlen,))\n",
    "    \n",
    "    embedding_layer = Embedding(\n",
    "        input_dim=embedding_matrix.shape[0],\n",
    "        output_dim=embedding_matrix.shape[1],\n",
    "        weights=[embedding_matrix],\n",
    "        input_length=maxlen,\n",
    "        trainable=False)\n",
    "    \n",
    "    gru_layer = Bidirectional(GRU(64, return_sequences=True))\n",
    "    \n",
    "    attention_layer = Attention(maxlen)\n",
    "    attention_output_1 = attention_layer(gru_layer(embedding_layer(input_1)))\n",
    "    attention_output_2 = attention_layer(gru_layer(embedding_layer(input_2)))\n",
    "    \n",
    "    \n",
    "    concat_layer = concatenate([attention_output_1, attention_output_2])\n",
    "    \n",
    "    x = Dropout(0.2)(concat_layer)\n",
    "    x = BatchNormalization()(x)\n",
    "    x = Dense(300, activation='relu')(x)\n",
    "\n",
    "    x = Dropout(0.2)(x)\n",
    "    x = BatchNormalization()(x)\n",
    "    pred = Dense(1, activation='sigmoid')(x)\n",
    "\n",
    "    model = Model([input_1,input_2],pred)\n",
    "    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc'])\n",
    "    return model\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__________________________________________________________________________________________________\n",
      "Layer (type)                    Output Shape         Param #     Connected to                     \n",
      "==================================================================================================\n",
      "input_3 (InputLayer)            (None, 20)           0                                            \n",
      "__________________________________________________________________________________________________\n",
      "input_4 (InputLayer)            (None, 20)           0                                            \n",
      "__________________________________________________________________________________________________\n",
      "embedding_2 (Embedding)         (None, 20, 300)      39264300    input_3[0][0]                    \n",
      "                                                                 input_4[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "bidirectional_1 (Bidirectional) (None, 20, 128)      140160      embedding_2[0][0]                \n",
      "                                                                 embedding_2[1][0]                \n",
      "__________________________________________________________________________________________________\n",
      "attention_1 (Attention)         (None, 128)          148         bidirectional_1[0][0]            \n",
      "                                                                 bidirectional_1[1][0]            \n",
      "__________________________________________________________________________________________________\n",
      "concatenate_4 (Concatenate)     (None, 256)          0           attention_1[0][0]                \n",
      "                                                                 attention_1[1][0]                \n",
      "__________________________________________________________________________________________________\n",
      "dropout_4 (Dropout)             (None, 256)          0           concatenate_4[0][0]              \n",
      "__________________________________________________________________________________________________\n",
      "batch_normalization_4 (BatchNor (None, 256)          1024        dropout_4[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dense_4 (Dense)                 (None, 300)          77100       batch_normalization_4[0][0]      \n",
      "__________________________________________________________________________________________________\n",
      "dropout_5 (Dropout)             (None, 300)          0           dense_4[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "batch_normalization_5 (BatchNor (None, 300)          1200        dropout_5[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dense_5 (Dense)                 (None, 1)            301         batch_normalization_5[0][0]      \n",
      "==================================================================================================\n",
      "Total params: 39,484,233\n",
      "Trainable params: 218,821\n",
      "Non-trainable params: 39,265,412\n",
      "__________________________________________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "rnn_model = RNN_Model(embedding_matrix)\n",
    "rnn_model.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Training RNN model ##\n",
    "\n",
    "[Go up](#Table-of-contents)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 323432 samples, validate on 80858 samples\n",
      "Epoch 1/2\n",
      "323432/323432 [==============================] - 583s 2ms/step - loss: 0.2389 - acc: 0.7197 - val_loss: 0.4639 - val_acc: 0.7666\n",
      "Epoch 2/2\n",
      " 86816/323432 [=======>......................] - ETA: 6:29 - loss: 0.2156 - acc: 0.7539"
     ]
    }
   ],
   "source": [
    "rnn_history = rnn_model.fit([train_padded['sequence_1'],train_padded['sequence_2']], train_y, class_weight={0:0.64,1:0.36},\n",
    "             validation_data=([val_padded['sequence_1'], val_padded['sequence_2']], val_y), verbose=1, epochs = 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Validation and test set RNN ##\n",
    "\n",
    "[Go up](#Table-of-contents)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "80858/80858 [==============================] - 50s 618us/step\n",
      "[0.4297571598786144, 0.7898909198886644]\n",
      "CPU times: user 4min 43s, sys: 50.5 s, total: 5min 34s\n",
      "Wall time: 1min 39s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "val_preds = rnn_model.predict([val_padded['sequence_1'], val_padded['sequence_2']])\n",
    "print(rnn_model.evaluate([val_padded['sequence_1'], val_padded['sequence_2']], val_y))\n",
    "submission = pd.DataFrame(index = val_data.index, columns = ['cv_id', 'is_duplicate'])\n",
    "submission['val_id'] = val_data.index\n",
    "submission['is_duplicate'] = val_preds\n",
    "submission.to_csv('val_rnn_submission.csv', index=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1h 8min 14s, sys: 12min 4s, total: 1h 20min 19s\n",
      "Wall time: 23min 43s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "rnn_predictions = rnn_model.predict([test_padded['sequence_1'],test_padded['sequence_2']])\n",
    "submission = pd.DataFrame(index = test_data.index, columns = ['test_id', 'is_duplicate'])\n",
    "submission['test_id'] = test_data.index\n",
    "submission['is_duplicate'] = rnn_predictions\n",
    "submission.to_csv('rnn_submission.csv', index=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Further improvements ##\n",
    "\n",
    "[Go up](#Table-of-contents)\n",
    "\n",
    "1. Tfidf weighted word embeddings for everything\n",
    "2. fuzzy features"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
